package mspbots.cw.business.core.boards;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mspbots.cw.business.core.BaseReceiver;
import mspbots.cw.common.ResultMsg;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.time.Duration;
import java.util.Iterator;

/**
 * @author Jay.Yang
 */
@Log4j2
@Component
@RequiredArgsConstructor
public class BoardsReceiver extends BaseReceiver {

    private final BoardsRepository boardsRepository;
    private final BoardStatusRepository boardStatusRepository;
    private final BoardTypesRepository boardTypesRepository;

    @RabbitListener(queues = "connect-wise.boards.tl")
    public void process(ResultMsg resultMsg) {
        JsonNode entity = resultMsg.getEntity();
        Boards data = super.objectMapper.convertValue(entity, Boards.class);
        data.setId(null);
        data.setCwId(resultMsg.getId());
        data.setTenantCode(resultMsg.getTenantId());
        data.setSyncTime(resultMsg.getSyncDate());
        data.setLastUpdated(ObjectUtils.isEmpty(entity.get("_info")) ? null : super.getDateTimeValue(entity.get("_info").get("lastUpdated")));
        this.boardsRepository.findByCwIdAndTenantCode(resultMsg.getId(), resultMsg.getTenantId())
                .map(result -> {
                    data.setId(result.getId());
                    return data;
                })
                .defaultIfEmpty(data)
                .flatMap(this.boardsRepository::save).block(Duration.ofSeconds(10));
        this.processBoardStatus(resultMsg);
        this.processBoardTypes(resultMsg);
    }

    private void processBoardStatus(ResultMsg resultMsg) {
        JsonNode statusNode = resultMsg.getEntity().get("status");
        if (ObjectUtils.isEmpty(statusNode) || statusNode.isEmpty()) {
            return;
        }
        Iterator<JsonNode> elements = statusNode.elements();
        while (elements.hasNext()) {
            JsonNode next = elements.next();
            try {
                Long cwId = super.getLongValue(next.get("id"));
                BoardStatus data = super.objectMapper.convertValue(next, BoardStatus.class);
                data.setId(null);
                data.setCwId(cwId);
                data.setBoardId(super.getLongValueId(next.get("board")));
                data.setBoardName(super.getStringValueName(next.get("board")));
                data.setTenantCode(resultMsg.getTenantId());
                data.setSyncTime(resultMsg.getSyncDate());
                data.setLastUpdated(super.getDateTimeValue(next.findValue("lastUpdated")));
                this.boardStatusRepository.findByCwIdAndTenantCode(cwId, resultMsg.getTenantId())
                        .map(result -> {
                            data.setId(result.getId());
                            return data;
                        })
                        .defaultIfEmpty(data)
                        .flatMap(this.boardStatusRepository::save).block(Duration.ofSeconds(10));
            } catch (IllegalArgumentException e) {
                log.error("------------board status parse error!!!---------data:{}", next);
                log.error(e.getMessage());
            }
        }
    }

    private void processBoardTypes(ResultMsg resultMsg) {
        JsonNode typesNode = resultMsg.getEntity().get("types");
        if (ObjectUtils.isEmpty(typesNode) || typesNode.isEmpty()) {
            return;
        }
        Iterator<JsonNode> elements = typesNode.elements();
        while (elements.hasNext()) {
            JsonNode next = elements.next();
            try {
                Long cwId = super.getLongValue(next.get("id"));
                BoardTypes data = super.objectMapper.convertValue(next, BoardTypes.class);
                data.setId(null);
                data.setCwId(cwId);
                data.setBoardId(super.getLongValueId(next.get("board")));
                data.setBoardName(super.getStringValueName(next.get("board")));
                data.setTenantCode(resultMsg.getTenantId());
                data.setSyncTime(resultMsg.getSyncDate());
                data.setLastUpdated(super.getDateTimeValue(next.findValue("lastUpdated")));
                this.boardTypesRepository.findByCwIdAndTenantCode(cwId, resultMsg.getTenantId())
                        .map(result -> {
                            data.setId(result.getId());
                            return data;
                        })
                        .defaultIfEmpty(data)
                        .flatMap(this.boardTypesRepository::save).block(Duration.ofSeconds(10));
            } catch (IllegalArgumentException e) {
                log.error("------------board types parse error!!!---------data:{}", next);
                log.error(e.getMessage());
            }
        }
    }

}
